<? // lib

// set global $_subdomain
$_subdomain = substr($_SERVER['SERVER_NAME'],0,strpos($_SERVER['SERVER_NAME'],'.'));
if( $_subdomain == 'www' ) $_subdomain = null;

// database - - - - - - - - - - - - - - - - - - - -

// parameters to set in each instance
$db_params = Array(

	// the select, dml and shadow users - login and password
	'dbUsers' => Array(
		'select'=>Array('user'=>'mselect', 'pwd'=>'mselect', 'table_grant'=>'select', 'tables_revoke'=>Array('shadow') ),
		'dml'=>Array('user'=>'mdml', 'pwd'=>'mdml', 'table_grant'=>'select,insert,update,delete', 'tables_revoke'=>Array('shadow') ),
		'shadow'=>Array('user'=>'mlogin', 'pwd'=>'mlogin', 'functions_grant'=>Array('login'), 'procedures_grant'=>Array('set_password') ) ),

	// if parameter has this value then will be passed through as function
	'dbFuncs' => Array( 'current_date', 'current_time', 'current_timestamp' ),
	
	// variable name or constant for the schema used in connection
	'schemaVar' => '$_subdomain'
);

// user: select, dml, shadow; mysqli: whether mysqli connection (should be true for dml)
function db_connect( $dbUser, $mysqli=false ) {
GLOBAL $db_params;

	// connection name - set globally
	$gname = "_{$dbUser}DB".(($mysqli)?'i':'');

	// set session
	if( !isset($db_params['dbUsers'][$dbUser]) ) ajax_exit( 'failure', "unable to use dbuser=$dbUser" );
	if( substr($db_params['schemaVar'],0,1)=='$' )	$schema = $GLOBALS[substr($db_params['schemaVar'],1)];

	// if connection already set, return it
	if( isset($GLOBALS[$gname]) ) return $GLOBALS[$gname];

	// new connection: mysqli
	if( $mysqli ) {
		$GLOBALS[$gname] = new mysqli( 'localhost', $db_params['dbUsers'][$dbUser]['user'], $db_params['dbUsers'][$dbUser]['pwd'], $schema );
		// todo: connection error
	}
	// new connection: classic
	else {
		$GLOBALS[$gname] = mysql_pconnect( 'localhost', $db_params['dbUsers'][$dbUser]['user'], $db_params['dbUsers'][$dbUser]['pwd'] );
		// todo: connection error
		if( $schema )  mysql_select_db( $schema, $GLOBALS[$gname] );
	}

	return $GLOBALS[$gname];
}

// session - - - - - - - - - - - - - - - - - - - -
session_start();

// initial session
if( !count( $_SESSION ) ) $_SESSION = array(
	'usr_id'	=> null,	// id into users table
	'login'		=> null,	// users.name
	'name'		=> null,	// users.login
	'login_ts'	=> null,	// when logged in - null if not
	'prv_hash'	=> null,	// previous hash
	'cur_hash'	=> mt_rand( 0, 1073741823 ),	// current hash (from client if first access)
	//='cur_hash'	=> 123456789,	// current hash (from client if first access)
	'pgn_url'	=> null );	// url source of pgn
$_SESSION['prv_uri'] = @$_SESSION['cur_uri'];
$_SESSION['cur_uri'] = $_SERVER['REQUEST_URI'];


// utility functions - - - - - - - - - - - - - - - - - - - -

// ajax error - error status and exit for ajax calls
function ajax_exit( $status, $msg, $arr=null ) {
	$jason_arr = array( 'status'=>$status, 'message'=>$msg );
	$_SESSION['prv_hash'] = $_SESSION['cur_hash'];
	$_SESSION['cur_hash'] = mt_rand( 0, 1073741823 );
	//=$_SESSION['cur_hash'] = 123456789;
	$jason_arr['hash'] = $_SESSION['cur_hash'];
	if( $arr ) foreach( $arr as $key=>$val ) $jason_arr[$key] = $val;
	echo json_encode( $jason_arr );
	exit;
}

// login / password
function db_login( $user, $pwd ) {
	$_db = db_connect('shadow');
	$result = mysql_query( "select login('$user','$pwd')", $_db );
	// for now do not catch errors - explode
	if( !mysql_num_rows($result) ) return null;
	$row = mysql_fetch_array( $result );
	return $row[0];
}
function db_password( $usr_id, $pwd ) {
	$mysqli = db_connect('shadow',true);
	$stmt = $mysqli->prepare( "call set_password( ?, ? )" );
	if( !$stmt ) ajax_exit( 'failure', "internal error: mysqli unable to prepare \"$query\"" );
	$stmt->bind_param( 'is', $usr_id, $pwd );
	$stmt->execute();
	$stmt->close();
}

// select
function db_get_rcd( $query ) {
	$_db = db_connect('select');
	$result = mysql_query( $query, $_db );
	// for now do not catch errors - explode
	if( !$result ) ajax_exit( 'error', "db_get_rcd( '".$query.'" )' );
	if( !mysql_num_rows($result) ) return array();
	$rcd = mysql_fetch_assoc( $result );
	mysql_free_result($result);
	return $rcd;
}
function db_get_rcds( $query ) {
	$_db = db_connect('select');
	$arr = Array();
	$result = mysql_query( $query, $_db );
	// for now do not catch errors - explode
	if( !$result ) ajax_exit( 'error', "db_get_rcd( '".$query.'" )' );
	while( $rcd = mysql_fetch_assoc( $result ) ) $arr[] = $rcd;
	mysql_free_result($result);
	return $arr;
}
function db_get_col( $query ) {
	$_db = db_connect('select');
	$result = mysql_query( $query, $_db );
	// for now do not catch errors - explode
	if( !mysql_num_rows($result) ) return null;
	$row = mysql_fetch_array( $result );
	mysql_free_result($result);
	return $row[0];
}

// dml
function db_dml( $query ) {
GLOBAL $db_params;

	// classical
	if( func_num_args()==1 ) {
		$_db = db_connect('dml');
		$result = @mysql_query( $query, $_db );
		if( !$result ) ajax_exit( 'failure', mysql_error() );
		return mysql_affected_rows( $_db );
	}

	// parameterized
	else {
		$mysqli = db_connect( 'dml', true );
		$queryArr = explode( '?', $query );
		$newArr = Array( $queryArr[0] );

		// if second arg is array, use it for params; otherwise use cdr args
		if( gettype(func_get_arg(1)) == 'array' ) $params = func_get_arg(1);
		else {
			$params = func_get_args();
			array_shift( $params );
		}
		$paramCt = count($params);

		// place args into variables so can be passed by ref
		$types = '';
		for( $i=1, $j=0; $j<count($params); $j++ ) {
			$var = "a$i";
			$$var = $params[$j];
			// kludge: hardwire NULL and common/safe mysql funcs
			if( $$var===null || in_array( strtolower($$var), $db_params['dbFuncs'] ) ) {
				//-if(!$$var) ajax_exit( 'failure', 'null parameter' );
				$newArr[count($newArr)-1] = $newArr[count($newArr)-1] . (($$var)?$$var:'null') . $queryArr[$j+1];
				$paramCt--;
				continue;
			}
			if( gettype($$var) == 'boolean' ) $$var = ($$var) ? 1 : 0;
			if( gettype($$var) == 'string' ) $types .= 's';
			elseif( gettype($$var) == 'integer' ) $types .= 'i';
			elseif( gettype($$var) == 'double' ) $types .= 'd';
			//-elseif( gettype($$var) == 'NULL' ) $types .= 'i';
			else ajax_exit( 'failure', "unhandled type: ".gettype($$var)." = ".$$var );
			$newArr[] = $queryArr[$j+1];
			$i++;
		}
		// put query back together
		$query = implode( '?', $newArr );
		//-@ajax_exit( 'failure', "query: $query, params: a1=$a1, a2=$a2, a3=$a3, a4=$ar, a5=$a5" );
		$stmt = $mysqli->prepare( $query );
		if( !$stmt ) ajax_exit( 'failure', "internal error: mysqli unable to prepare \"$query\"" );
		// must use eval for bind function
		for( $args = "\$types", $i=1; $i<=$paramCt; $i++ ) $args .= ", \$a$i";
		eval( "\$stmt->bind_param( $args );" );
		$stmt->execute();
		$ct = $stmt->affected_rows;
		$stmt->close();
		return $ct;
	}
}

// mysql_insert_db() - using mysqli if connection exists, otherwise dml connection
function db_insert_id() {
	// parameterized
	if( $GLOBALS["_dmlDBi"] ) return  $GLOBALS["_dmlDBi"]->insert_id;
	// classical
	if( $GLOBALS["_dmlDB"] ) return mysql_insert_id($GLOBALS["_dmlDB"]);
	// oops
	ajax_exit( 'failure', "cannot find previous connection for db_insert_id()" );
}


// pure funcs
function pure_code( $str ) {
	$str = strToLower($str);
	preg_match( '/^([a-z_][a-z0-9_]*)/', $str, $match_arr );
	return ( $match_arr[1] ) ? $match_arr[1] : null;
}
function pure_email( $str ) {
	// ((non-chars|^)(chars@chars)(non-chars|$))[2]
	return $str;
}
function pure_url( $str ) {
	// make sure begin with http, https, or ftp - right?
	return $str;
}
function pure_string( $str ) {
	return mysql_real_escape_string($str);
}
function pure_integer( $str ) {
	return (int)$str;
}
function pure_clause( $str ) {
	foreach( Array( ';', 'select', 'insert', 'update', 'delete' ) as $reserved )
		if( strpos( $reserved, strtolower($str) ) ) ajax_exit( 'failure', "Security Violation: sql clause = \"$str\"" );
	return $str;
}


?>
